

function H5sPlayerRtc(config) {
  this.connected = 0;
  this.request = null;
  this.hangingGet = null;
  this.localName = config.camera_view;
  this.myId = -1;
  this.clientId = -1;
  this.pc = -1;
  this.pcConfig;
  this.remoteStream;
  this.callback = null;
  this.mediaStream = null;
  this.mediaRecorder = null;
  this.recordedBlobs = null;
  this.respTime = 0;
  this.fpg = 15;
  this.live_stream = 0;
  this.streamer_peer_id = 0;
  this.old_candidate = -1;
  this.fps = 15;
  this.orgVideoWidth = 0;
  this.orgVideoHeight = 0;
  this.dotTimer = 0;
  this.videoid;
  this.remoteVideoId = document.getElementById(config.videoid)
  this.otherPeers = {};
  this.host = config.host;
  this.url = config.url;
  this.camera_view = config.camera_view;
  this.sessionTimer;

  RTCPeerConnection = window.mozRTCPeerConnnection ||
    window.webkitRTCPeerConnection || 
    window.RTCPeerConnection;

  RTCSessionDescription = window.mozRTCSessionDescription ||
    window.RTCSessionDescription;
  RTCIceCandidate = window.mozRTCIceCandidate ||
    window.RTCIceCandidate;
  // getUserMedia = navigator.mozGetUserMedia || navigator.webkitGetUserMedia;
  window.URL = window.webkitURL || window.URL;
}


H5sPlayerRtc.prototype.createPeerConnection = function(peer_id) {
  var _this = this
  trace('createPeerConnection' + peer_id);
  _this.clientId = peer_id;
  try {
    trace('Creating RTCPeerConnection');
    this.pc = new RTCPeerConnection();
    this.pc.onicecandidate = function (event)  {
      if (event.candidate) {
        const candidate = {
          sdpMLineIndex: event.candidate.sdpMLineIndex,
          sdpMid: event.candidate.sdpMid,
          candidate: event.candidate.candidate,
        };
        sendToPeer.call(_this, _this.clientId, JSON.stringify(event.candidate));
      } else {
        trace("End of Sending ICE Candidates");
      }
    }
    this.pc.oniceconnectionstatechange = function(event) {
      trace("ICE STATE " + _this.pc.iceConnectionState);
      if (_this.pc.iceConnectionState === "connected") {
        clearTimeout(_this.sessionTimer);
        _this.connected = 1;
        if (_this.live_stream === 0) {
          if (_this.camera_view.length == 0)
            alert("Enter valid camera view. i.e \ncamera_1");
          else changeView.call(_this, _this.camera_view);
        }
      } else if (_this.pc.iceConnectionState === "closed") {
        _this.connected = 0;
      } else if (_this.pc.iceConnectionState === "failed"){
        // 极有可能出现ice建立连接失败的情况
        // _this.callback(-1)
      }
    }
      
    this.pc.ontrack = onRemoteTrackAdded.bind(this);
    this.pc.onconnecting = onSessionConnecting;
    this.pc.onopen = onSessionOpened;
    this.pc.onremovestream = onRemoteStreamRemoved.bind(this)
  } catch (e) {
    trace(
      "Failed to create PeerConnection with " +
        this.connectionId +
        ", exception: " +
        e.message
    );
  }
} 





H5sPlayerRtc.prototype.oniceconnectionstatechange = function(event) {
  trace("ICE STATE " + this.pc.iceConnectionState);
  if (this.pc.iceConnectionState === "connected") {
    clearTimeout(this.sessionTimer)
    this.connected = 1;
    if (this.live_stream === 0) {
      if (this.camera_view.length === 0) {
        alert("Enter valid camera view. i.e \ncanmera_1")
      } else {
        changeView.call(this, this.camera_view)
      }
    } else if (this.pc.iceConnectionState === "closed") {
      this.connected = 0
    }
  }
}


function onRemoteTrackAdded (event) {
  let _this = this
  // trace("Remote track added: " + event.streams[0]);
  this.remoteVideoId.srcObject = event.streams[0];
  this.remoteVideoId.play();
  this.live_stream = 1;
}

// H5sPlayerRtc.prototype.onAddStream = function (event) {
//   var _this = this
//   var options = {
//     type: "video/webm;codecs=h264"
//   }
//   this.mediaRecorder = new MediaRecorder(event.stream, options)
//   this.recordedBlobs = []
//   if (this.mediaRecorder) {
//     this.recordedBlobs = []
//     this.mediaRecorder.onstop = handleStop.bind(this)
//     this.mediaRecorder.ondataavailable = handleDataAvailable.bind(this)
//     this.mediaRecorder.start();
//     console.log('MediaRecorder started', this.mediaRecorder);
//   }
// }


function onRemoteStreamRemoved (event) {
  trace("Remote stream removed.");
}

H5sPlayerRtc.prototype.signInCallback = function () {
  try {
    if (this.request.readyState == 4 
        && this.request.status == 200) {
      let peers = this.request.responseText.split("\n");
      console.log('peers', peers)
      this.myId = parseInt(peers[0].split(",")[1]);
      trace("My Peer ID: " + this.myId);
      for (let i = 1; i < peers.length; ++i) {
        if (peers[i].length > 0) {
          trace("Peer " + i + ": " + peers[i]);
          let parsed = peers[i].split(",");
          this.otherPeers[parseInt(parsed[1])] = parsed[0];
          if (this.streamer_peer_id === 0) {
            this.streamer_peer_id = parseInt(parsed[1]);
            trace("Sending Notification to peer = " + this.streamer_peer_id);
          }
        }
      }
      this.startHangingGet()
      this.request = null
    } else if (this.request.status === 500){
      // 服务器异常
      this.callback(-1)
      // this.disconnect()
    }
  } catch (e) {
    // this.callback(-1)
    throw new Error('登录失败')
    trace("error: " + e.description);
  }
}

H5sPlayerRtc.prototype.startHangingGet = function () {
  let _this = this
  try {
    this.hangingGet = new XMLHttpRequest();
    this.hangingGet.onreadystatechange = function () {
      hangingGetCallback.call(_this)
    }
    this.hangingGet.ontimeout = function () {
      onHangingGetTimeout.call(_this)
    };
    this.hangingGet.open("GET", this.server + "/wait?peer_id=" + this.myId, true);
    this.hangingGet.send()
  } catch (e) {
    trace("error" + e.description)
  }
}

// 截取图片
H5sPlayerRtc.prototype.capaturePicture = function () {
  if (this.remoteVideoId) {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d')
    canvas.width = this.remoteVideoId.clientWidth;
    canvas.height = this.remoteVideoId.clientHeight;
    ctx.drawImage(this.remoteVideoId, 0, 0, this.remoteVideoId.clientWidth, this.remoteVideoId.clientHeight)
    saveImage(canvas)
  }
}

// 开始录制视频
H5sPlayerRtc.prototype.startRecord = function () {
  let options = {
    type: "video/webm;codecs=h264"
  }
  this.mediaRecorder = new MediaRecorder(event.stream, options)
  this.recordedBlobs = []
  if (this.mediaRecorder) {
    this.recordedBlobs = []
    this.mediaRecorder.onstop = handleStop.bind(this)
    this.mediaRecorder.ondataavailable = handleDataAvailable.bind(this)
    this.mediaRecorder.start();
    console.log('MediaRecorder started', this.mediaRecorder);
  }
}


// 停止录制视频
H5sPlayerRtc.prototype.stopRecord = function (){
  if (this.mediaRecorder) {
    this.mediaRecorder.stop()
    console.log('record data', this.recordedBlobs)
  }
}


// 获取当前配置
H5sPlayerRtc.prototype.getConfig = function () {
  return {
    camera_view: this.camera_view,
    videoid: this.remoteVideoId,
    host: this.host
  }
}

function handleStop (event) {
  console.log('recorder stopped: ', event);
  saveVideo.call(this, "record.webm")
}

function handleDataAvailable (event) {
  this.recordedBlobs.push(event.data)
}

// 保存录像视频
function saveVideo(filename) {
  console.log('recordBlobs', this.recordedBlobs)
  const blob = new Blob(this.recordedBlobs, {
    type: "video/webm"
  });
  console.log('revert blob', blob)
  const url = window.URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.style.display = 'none';
  a.href = url;
  //文件名 通过方法传进来 检测是否合法？
  a.download = filename;
  document.body.appendChild(a);
  a.click();
  window.URL.revokeObjectURL(blob)
}

// 保存图片
function saveImage(canvas) {
  const image = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream');
  saveFile(image, 'file_' + new Date().getTime() + '.png');
}

// 保存文件
function saveFile(data, filename) {
  const save_link = document.createElement('a')
  save_link.href = data;
  save_link.download = filename;
  save_link.click()
}

function sendToPeer(peer_id, data) {
  try {
    if (this.myId == -1) {
      alert("Not connected");
      return;
    }
    if (peer_id == this.myId) {
      alert("Can't send a message to onself: ");
      return;
    }

    let r = new XMLHttpRequest()
    r.onreadystatechange = () => {
      if (r.status === 500) {
        this.callback(-1)
      }
    };
    r.open(
      "POST",
      this.server + "/message?peer_id=" + this.myId + "&to=" + peer_id,
      true
    );
    r.setRequestHeader("Content-Type", "text/plain");
    r.send(data);

  } catch (e) {
    trace("send to peer error: " + e.description);
  }

}

function onHangingGetTimeout() {
  let _this = this
  trace("hanging get timeout. issuing again.");
  this.hangingGet.abort();
  this.hangingGet = null;
  if (this.myId != -1) {
    window.setTimeout(this.startHangingGet.bind(_this), 0);
  }
}

function hangingGetCallback() {
  let _this = this
  if (this.hangingGet.readyState != 4) return;
    if (this.hangingGet.status != 200) {
      trace("server error: " + this.hangingGet.statusText);
      this.disconnect();
      trace("Returning");
      return;
    } else {
      const peer_id = parseIntHeader(this.hangingGet, "Pragma");
      // trace("Message from:" + peer_id + ":" + this.hangingGet.responseText);
      console.log('peer_id', peer_id, this.myId)
      if (peer_id == this.myId) {
        handleServerNotification.call(this, this.hangingGet.responseText);
      } else {
        if (this.streamer_peer_id === 0) {
          this.streamer_peer_id = peer_id
        }
        handlePeerMessage.call(this, peer_id, this.hangingGet.responseText)
      }
    }
    if (this.hangingGet) {
      this.hangingGet.abort();
      this.hangingGet = null;
    }
    if (this.myId != -1) {
      window.setTimeout(this.startHangingGet.bind(_this), 0);
    }
}

// 登录
H5sPlayerRtc.prototype.signIn = function () {
  const _this = this
  this.request = new XMLHttpRequest()
  this.request.onreadystatechange =  function () {
    _this.signInCallback()
  }
  this.request.open("GET", this.server + "/sign_in?" + this.localName, true);
  this.request.send()
}

// 建立连接
H5sPlayerRtc.prototype.connect = function (callback) {
  this.respTime = new Date();
  this.server = "http://" + this.host;
  this.callback = callback
  if (this.localName.length === 0) {
    alert("I need a name please.");
  } else {
    this.signIn()
    this.sessionTimer = setTimeout(sessionTimeout.bind(this), 30000)
  }
}

// 关闭连接
H5sPlayerRtc.prototype.disconnect = function () {
  let _this = this
  trace("disconnect() +");
  clearTimeout(this.sessionTimer)
  if (this.request) {
    this.request.abort()
    this.request = null
  }

  if (this.hangingGet) {
    this.hangingGet.abort()
    this.hangingGet = null
  }
  
  if (this.pc != -1) {
    this.pc.close();
    this.pc = -1;
  }
  this.streamer_peer_id = 0;
  if (this.myId !== -1) {
    this.request = new XMLHttpRequest();
    this.request.onreadystatechange = function () {
      onSignoutGetCallback.bind(_this);
    } 
    this.request.ontimeout = onSignoutGetTimeout;
    this.request.open("GET", this.server + "/sign_out?peer_id=" + this.myId, true)
    this.request.send();
    this.myId = -1;
  }
  this.connected = 0;
  this.live_stream = 0;
  trace("disconnect() -");
}

// 暂停视频流的播放
H5sPlayerRtc.prototype.mute = function () {
  if (this.remoteVideoId) {
    this.remoteVideoId.srcObject.getTracks().forEach(t => t.enabled = !t.enabled)
  }
}

H5sPlayerRtc.prototype.startPlaying = function () {
  trace("Started playing...");
  this.remoteVideoId.poster = ""
  const selector = this.pc.getReceivers()[0].track;
}

H5sPlayerRtc.prototype.send = function (text) {
  sendToPeer.call(this, this.peer_id, text);
}

function onSignoutGetCallback() {
  trace("onSignoutGetCallback() +");
  try {
    if (this.request.readyState == 4) {
      if (this.request.status == 200) {
        this.request = null;
      }
    }
  } catch (e) {
    trace("error: " + e.description);
  }
  trace("onSignoutGetCallback() -");
}

function onSignoutGetTimeout() {
  trace("onSignoutGetTimeout() +");
  trace("onSignoutGetTimeout() -");
}


function onSessionConnecting(message) {
  trace("Session connecting.");
}

function onSessionOpened(message) {
  trace("Session opened.");
}

function sessionTimeout () {
  this.callback(-1)
  this.disconnect()
  // alert("Unable to create connection to the vehicle!");
}

function handleServerNotification (data) {
  trace("Server notification: ", data);
  const parsed = data.split(",");
  if (parseInt(parsed[2]) != 0) this.otherPeers[parseInt(parsed[1])] = parsed[0];
}

function handlePeerMessage (peer_id, data) {
  let _this = this
  let dataJson = JSON.parse(data);
  if (dataJson.hasOwnProperty("sdp")) {
    if (this.pc === -1) this.createPeerConnection(peer_id)
    if (this.old_candidate !== -1) {
      trace("setting old ICE");
      this.pc.addIceCandidate(this.old_candidate);
      this.old_candidate = -1;
    }

    try {
      this.pc.setRemoteDescription(dataJson)
        .then(function () {
          trace("after setRemoteDescription")
          return _this.pc.createAnswer()
        })
        .then(function (answer)  {
          console.log("ANSWER = " + JSON.stringify(answer));
          const _sdp = answer.sdp;
          answer.sdp = updateSdp(_sdp);
          trace("after createAnswer = " + JSON.stringify(answer));
          _this.pc.setLocalDescription(answer);
          trace("after setLocalDescription call");
          sendToPeer.call(_this, _this.clientId, JSON.stringify(answer));
        })
    } catch (e) {
      trace("setRemoteDescription raised exception");
    }
  } else if (dataJson.hasOwnProperty("vehicle_resp")) {
    console.log("Vehicle Response = " + dataJson["vehicle_resp"]);
    this.disconnect()
  } else {
    if (this.pc === -1) {
      trace("Unable to set ACE since pc == -1");
      if (this.old_candidate === -1) {
        trace("Saving for future");
        this.old_candidate = new RTCIceCandidate({
          candidate: dataJson.cadidate,
          sdpMid: dataJson.sdpMid,
          sdpMLineIndex: dataJson.sdpMLineIndex,
        });
      }
      // this.callback(-1)
      // this.disconnect()
    } else {
      trace("Adding ICE Candidate = " + data);
      let candidate = new RTCIceCandidate({
        candidate: dataJson.candidate,
        sdpMid: dataJson.sdpMid,
        sdpMLineIndex: dataJson.sdpMLineIndex,
      });
      this.pc.addIceCandidate(candidate)
    }
  }
}

function updateSdp(_sdp) {
  let data_after_split = JSON.stringify(_sdp).split("\\r\\n");
  let data_new = "";
  let h264_codec = "";
  for (let i = 0; i < data_after_split.length; i++) {
    if (
      data_after_split[i].includes("rtpmap:") === true &&
      data_after_split[i].includes("H264") === true
    ) {
      const temp1 = data_after_split[i].split(" ");
      const temp2 = temp1[0].split(":");
      h264_codec = temp2[1];
      console.log("Found H264 Codec = " + h264_codec);
      break;
    }
  }
  for (let i = 0; i < data_after_split.length; i++) {
    //console.log("[" + i + " ] " + data_after_split[i])
    if (data_after_split[i].includes("m=video") === true) {
      //console.log(data_after_split[i])
      //data_after_split.splice(i);
      let temp = data_after_split[i].split(" ");
      if (h264_codec !== "" && temp[3] !== h264_codec) {
        data_new +=
          temp[0] + " " + temp[1] + " " + temp[2] + " " + h264_codec;
        for (let j = 3; j < temp.length; j++) {
          if (temp[j] != h264_codec) {
            data_new += " ";
            data_new += temp[j];
          }
        }
        console.log("Setting H264 Codec = " + h264_codec);
      } else {
        data_new += data_after_split[i];
      }
      data_new += "\\r\\n";
    } else {
      data_new += data_after_split[i];
      if (i < data_after_split.length - 1) data_new += "\\r\\n";
    }
  }
  return JSON.parse(data_new);
}

function parseIntHeader(r, name) {
  let val = r.getResponseHeader(name);
  return val != null && val.length ? parseInt(val) : -1;
}

function changeView (viewId) {
  let data = { camera_view: viewId };
  let dataJson = JSON.stringify(data);
  sendToPeer.call(this, this.streamer_peer_id, dataJson)
}

function trace(txt) {
  //var elem = document.getElementById("log");
  //elem.innerHTML += txt + "<br>";
  console.log(txt);
}

function dummy () {

}


export {
  H5sPlayerRtc
}

